package com.evil.application.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.word.WordExportUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.WorkbookUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.account.api.RemoteUserService;
import com.evil.application.api.RemoteApplicationPrintTemplateService;
import com.evil.application.enums.ImportTemplateTypeEnum;
import com.evil.application.mapper.ApplicationInfoMapper;
import com.evil.application.mapper.ApplicationOrderMapper;
import com.evil.application.mapper.ApplicationPrintTemplateMapper;
import com.evil.application.pojo.dto.template.UploadTemplateReqDTO;
import com.evil.application.pojo.dto.template.print.*;
import com.evil.application.pojo.entity.ApplicationInfo;
import com.evil.application.pojo.entity.ApplicationPrintTemplate;
import com.evil.application.service.ApplicationFormControlService;
import com.evil.application.service.ApplicationOrderDataService;
import com.evil.application.service.ApplicationPrintTemplateService;
import com.evil.application.service.ElasticsearchService;
import com.evil.application.util.ApplicationPrintUtil;
import com.evil.application.util.ApplicationUtil;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.form.control.ControlBaseDTO;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.enums.ApplicationVersionEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.file.constant.OssConstant;
import com.evil.common.file.dto.FileRespDTO;
import com.evil.common.file.dto.UploadReqDTO;
import com.evil.common.file.enums.BusTypeEnum;
import com.evil.common.file.util.PoiUtil;
import com.evil.file.api.RemoteFileService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 打印模板表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationPrintTemplateServiceImpl extends ServiceImpl<ApplicationPrintTemplateMapper, ApplicationPrintTemplate>
        implements ApplicationPrintTemplateService, RemoteApplicationPrintTemplateService {

    private final LoginUtil loginUtil;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final ApplicationOrderMapper applicationOrderMapper;

    private final ApplicationFormControlService applicationFormControlService;

    private final ApplicationOrderDataService applicationOrderDataService;

    private final ElasticsearchService elasticsearchService;

    private final RemoteUserService remoteUserService;

    private final RemoteUserEnterpriseService remoteUserEnterpriseService;

    private final RemoteFileService remoteFileService;

    private final ApplicationLogServiceImpl applicationLogService;

    /**
     * 获取打印模板列表
     *
     * @param printTemplateListReqDTO templateListReqDTO
     * @return List
     */
    @Override
    public List<PrintTemplateRespDTO> list(PrintTemplateListReqDTO printTemplateListReqDTO) {
        printTemplateListReqDTO.setEnterpriseId(loginUtil.getParamEnterpriseId(printTemplateListReqDTO.getEnterpriseId()));
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(printTemplateListReqDTO.getApplicationKey());
        printTemplateListReqDTO.setApplicationId(applicationInfo.getApplicationId());
        // 如果当前登录用户不是管理员，看不到任何模板
        if (remoteUserEnterpriseService.enterpriseManager(loginUtil.getLoginUserEnterprise())) {
            return this.baseMapper.printTemplateList(printTemplateListReqDTO).stream()
                    .map(e -> {
                        PrintTemplateRespDTO temp = BeanUtil.copyProperties(e, PrintTemplateRespDTO.class);
                        temp.setCreator(remoteUserService.findBaseById(e.getCreatorId()));
                        return temp;
                    }).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 新增打印模板
     *
     * @param savePrintTemplateReqDTO addUploadTemplateReqDTO
     */
    @Override
    public void save(SavePrintTemplateReqDTO savePrintTemplateReqDTO) {
        Long enterpriseId = loginUtil.getLoginEnterpriseId();
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(savePrintTemplateReqDTO.getApplicationKey());

        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());
        ApplicationPrintTemplate applicationPrintTemplate;
        if (savePrintTemplateReqDTO.getPrintTemplateId() != null) {
            // 校验模板是否存在
            applicationPrintTemplate = this.baseMapper.findById(savePrintTemplateReqDTO.getPrintTemplateId());
        } else {
            applicationPrintTemplate = new ApplicationPrintTemplate();
            // 生成key
            String templateKey = ApplicationUtil.generateKey(key -> this.baseMapper.isExistByKey(key).isPresent());
            applicationPrintTemplate.setTemplateKey(templateKey);
        }

        applicationPrintTemplate.setEnterpriseId(enterpriseId);
        applicationPrintTemplate.setApplicationId(applicationInfo.getApplicationId());
        applicationPrintTemplate.setTemplateType(savePrintTemplateReqDTO.getTemplateType());
        applicationPrintTemplate.setTemplateName(savePrintTemplateReqDTO.getFileName());
        applicationPrintTemplate.setFileId(savePrintTemplateReqDTO.getFileId());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPrintTemplate::getPrintTemplateId, applicationPrintTemplate);
    }

    /**
     * 重命名打印模板
     *
     * @param renamePrintTemplateReqDTO templateRenameReqDTO
     */
    @Override
    public void rename(RenamePrintTemplateReqDTO renamePrintTemplateReqDTO) {
        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        ApplicationPrintTemplate applicationPrintTemplate = this.baseMapper.findById(renamePrintTemplateReqDTO.getPrintTemplateId());
        // 检查企业
        loginUtil.checkEnterpriseId(applicationPrintTemplate.getEnterpriseId());

        applicationPrintTemplate.setTemplateName(renamePrintTemplateReqDTO.getTemplateName());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPrintTemplate::getPrintTemplateId, applicationPrintTemplate);
    }

    /**
     * 删除打印模板
     *
     * @param deletePrintTemplateReqDTO deleteTemplateReqDTO
     */
    @Override
    public void delete(DeletePrintTemplateReqDTO deletePrintTemplateReqDTO) {
        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        ApplicationPrintTemplate applicationPrintTemplate = this.baseMapper.findById(deletePrintTemplateReqDTO.getPrintTemplateId());

        applicationPrintTemplate.setIsDeleted(SwitchEnum.YES.getId());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPrintTemplate::getPrintTemplateId, applicationPrintTemplate);
    }

    /**
     * 打印模板详情
     *
     * @param printTemplateDetailReqDTO templateDetailReqDTO
     * @return TemplateRespDTO
     */
    @Override
    public PrintTemplateRespDTO detail(PrintTemplateDetailReqDTO printTemplateDetailReqDTO) {
        return BeanUtil.copyProperties(this.baseMapper.findById(printTemplateDetailReqDTO.getPrintTemplateId()), PrintTemplateRespDTO.class);
    }

    /**
     * 上传打印模板
     *
     * @param uploadTemplateReqDTO uploadTemplateReqDTO
     */
    @Override
    public FileRespDTO upload(UploadTemplateReqDTO uploadTemplateReqDTO) {
        ImportTemplateTypeEnum.findById(uploadTemplateReqDTO.getTemplateType());

        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(uploadTemplateReqDTO.getApplicationKey());
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        // 上传文件 新增file数据
        UploadReqDTO uploadReqDTO = new UploadReqDTO();
        uploadReqDTO.setEnterpriseId(uploadTemplateReqDTO.getEnterpriseId());
        uploadReqDTO.setFile(uploadTemplateReqDTO.getFile());
        uploadReqDTO.setType(uploadTemplateReqDTO.getType());
        uploadReqDTO.setUserId(uploadTemplateReqDTO.getUserId());
        uploadReqDTO.setAllowContentType(null);
        uploadReqDTO.setAllowMaxSize(OssConstant.UPLOAD_FILE_SIZE);
        return remoteFileService.uploadFile(uploadReqDTO);
    }

    /**
     * 下载打印模板
     *
     * @param downloadPrintTemplateReqDTO downloadTemplateReqDTO
     * @return FileRespDTO
     */
    @Override
    public FileRespDTO download(DownloadPrintTemplateReqDTO downloadPrintTemplateReqDTO) {
        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());
        // 校验模板是否存在
        ApplicationPrintTemplate applicationPrintTemplate = this.baseMapper.findById(downloadPrintTemplateReqDTO.getPrintTemplateId());
        if (applicationPrintTemplate.getFileId() == null) {
            throw new BusinessException(RCodeEnum.ERROR, "模板文件不存在");
        }

        return remoteFileService.findBaseByFileId(applicationPrintTemplate.getFileId());
    }

    /**
     * 打印模板数据
     *
     * @param printTemplateReqDTO printTemplateReqDTO
     */
    @Override
    public FileRespDTO printTemplate(PrintTemplateReqDTO printTemplateReqDTO) {
        // 校验订单是否存在
        applicationOrderMapper.findById(printTemplateReqDTO.getOrderId());

        // 校验模板是否存在
        ApplicationPrintTemplate printTemplate = this.baseMapper.findById(printTemplateReqDTO.getPrintTemplateId());

        // 获取订单详情
        List<ControlDataDTO> orderDataList = elasticsearchService.orderDataList(printTemplateReqDTO.getOrderId());
        // 订单控件数据map
        Map<Long, ControlDataDTO> controlDataMap = StreamUtil.toMapK(orderDataList, ControlDataDTO::getControlId);

        // 通过应用id获取模板配置
        ApplicationVersionEnum releaseVersion = ApplicationVersionEnum.RELEASE_VERSION;
        List<ControlBaseDTO> controlBases = applicationFormControlService.findBaseByAppId(printTemplate.getApplicationId(), releaseVersion, true);
        Map<String, Object> contentMap = ApplicationPrintUtil.generatePrintMap(controlBases, controlDataMap);

        return this.handlePrint(new HandlePrintTemplateDTO(contentMap, printTemplate.getFileId()));
    }

    /**
     * 处理打印
     *
     * @param handlePrintTemplateDTO printTemplateRespDTO
     */
    private FileRespDTO handlePrint(HandlePrintTemplateDTO handlePrintTemplateDTO) {
        // 从服务器获取打印模板
        FileRespDTO fileRespDTO = remoteFileService.findBaseByFileId(handlePrintTemplateDTO.getFileId());
        String fileName = fileRespDTO.getFileName();

        // 文件
        MultipartFile file;
        // 文件类型
        String allowContentType;
        // excel
        if (PoiUtil.isExcel03(fileName) || PoiUtil.isExcel07(fileName)) {
            Workbook workbook;
            try {
                TemplateExportParams templateExportParams = new TemplateExportParams();

                // 接收打印模板
                byte[] fileBytes = remoteFileService.getFileByteByFileBase(fileRespDTO);
                workbook = WorkbookUtil.createBook(new ByteArrayInputStream(fileBytes));
                templateExportParams.setTemplateWb(workbook);

                templateExportParams.setScanAllsheet(true);
                templateExportParams.setColForEach(true);
                workbook = ExcelExportUtil.exportExcel(templateExportParams, handlePrintTemplateDTO.getContentMap());

                // 处理打印定制-计算公式
                ApplicationPrintUtil.handlePrintCal(workbook);
            } catch (Exception e) {
                log.error("处理打印 | 异常", e);
                throw new BusinessException(RCodeEnum.PRINT_ERROR);
            }
            if (handlePrintTemplateDTO.getPreview()) {
                // 预览，则需要转换PDF
                file = PoiUtil.preview(workbook, fileName);
                allowContentType = OssConstant.PDF_CONTENT_TYPE;
            } else {
                file = PoiUtil.workbookToMultipartFile(workbook, fileName, false);
                allowContentType = OssConstant.UPLOAD_EXCEL_TYPE;
            }
        }
        // word
        else {
            XWPFDocument doc;
            try {
                doc = WordExportUtil.exportWord07(fileRespDTO.getFileUrl(), handlePrintTemplateDTO.getContentMap());
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException(RCodeEnum.PRINT_ERROR);
            }
            if (handlePrintTemplateDTO.getPreview()) {
                // 预览，则需要转换PDF
                file = PoiUtil.preview(doc, fileName);
                allowContentType = OssConstant.PDF_CONTENT_TYPE;
            } else {
                file = PoiUtil.docToMultipartFile(doc, fileName, false);
                allowContentType = OssConstant.UPLOAD_WORD_TYPE;
            }
        }

        // 上传文件 新增file数据
        UploadReqDTO uploadReqDTO = new UploadReqDTO();
        uploadReqDTO.setEnterpriseId(loginUtil.getLoginEnterpriseId());
        uploadReqDTO.setFile(file);
        // 应用打印文件
        uploadReqDTO.setType(BusTypeEnum.APPLICATION_PRINT_FILE.getId());
        uploadReqDTO.setUserId(loginUtil.getLoginUserId());
        uploadReqDTO.setAllowContentType(allowContentType);
        uploadReqDTO.setAllowMaxSize(OssConstant.UPLOAD_FILE_SIZE);
        uploadReqDTO.setIsPreview(handlePrintTemplateDTO.getPreview());
        return remoteFileService.uploadFile(uploadReqDTO);
    }
}
